package org.ph.share.lock.test.thread2;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 死锁探究
 * 5位哲学家有5根筷子，吃饭的时候需锁住俩根,从而导致死锁问题[哲学家进餐问题]
 * 使用ReentrantLock(可重入锁)改造
 *
 * @author Hush.
 * @since 2023/1/18 19:47
 */
@Slf4j
public class Thread8_1 {
    public static void main(String[] args) {
        Chopsticks_1 c1 = new Chopsticks_1("c1");
        Chopsticks_1 c2 = new Chopsticks_1("c2");
        Chopsticks_1 c3 = new Chopsticks_1("c3");
        Chopsticks_1 c4 = new Chopsticks_1("c4");
        Chopsticks_1 c5 = new Chopsticks_1("c5");
        new Philosopher_1("德谟克里特", c1, c2).start();
        new Philosopher_1("苏格拉底", c2, c3).start();
        new Philosopher_1("柏拉图", c3, c4).start();
        new Philosopher_1("亚里士多德", c4, c5).start();
        new Philosopher_1("普罗塔哥拉", c5, c1).start();
    }
}

/**
 * 哲学家类
 *
 * @author Hush.
 * @since 2023/5/18 22:16
 */
@Slf4j
class Philosopher_1 extends Thread {

    private final Chopsticks_1 left;
    private final Chopsticks_1 right;

    Philosopher_1(String name, Chopsticks_1 left, Chopsticks_1 right) {
        super(name);
        this.left = left;
        this.right = right;
    }

    @Override
    public void run() {
        while (true) {
            ReentrantLock leftLock = left.getLock();
            try {
                Thread.sleep((long) (Math.random() * 100));
                leftLock.lock();
                ReentrantLock rightLock = right.getLock();
                if (rightLock.tryLock()) {
                    try {
                        this.eat();
                    } finally {
                        rightLock.unlock();
                    }
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                leftLock.unlock();
            }
        }
    }

    public void eat() {
        try {
            TimeUnit.SECONDS.sleep(1);
            log.info("吃饭饭...");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

/**
 * 筷子对象
 *
 * @author Hush.
 * @since 2023/5/18 22:07
 */
class Chopsticks_1 {

    ReentrantLock lock = new ReentrantLock();
    /**
     * 名称
     */
    private final String name;

    Chopsticks_1(String name) {
        this.name = name;
    }

    public ReentrantLock getLock() {
        return lock;
    }

    public String getName() {
        return name;
    }
}